﻿using System.Collections.Generic;
using System.Diagnostics;
using Microsoft.Xna.Framework;
using Microsoft.Xna.Framework.Graphics.PackedVector;
using Microsoft.Xna.Framework.Net;
using TNCGameEngine.InternalHelpers;

namespace TNCGameEngine.Network.Data
{
    /// <summary>
    /// Defines a compressed data writer via the network.
    /// </summary>
    public abstract class CompressedWriter<T>
    {

        #region "Properties"
                
        private int writecount = 0;
        /// <summary>
        /// The current number of bytes written out.
        /// </summary>
        /// <remarks>Gets the number of bytes written since the last BeginWrite().</remarks>
        public int WriteCount
        {
            get { return this.writecount; }
        }
                
        #endregion

        #region "Variables"

        private PacketWriter writer = null;

        #endregion
                
        #region "Methods"

        /// <summary>
        /// The method that needs to be called by the derived constructor.
        /// </summary>
        /// <param name="writer">The packet writer that should be written to.</param>
        protected void PreInitialize(PacketWriter writer)
        {
            this.writer = writer;
        }

        /// <summary>
        /// Writes a list of bool values into the associated packet writer compressed into bytes.
        /// </summary>
        /// <param name="list">List of bool values to be sent as a batch.</param>
        /// <returns>Number of successful bytes written.</returns>
        protected int WriteBools(List<bool> list)
        {

            int i = 0;
            try
            {

                int count = list.Count;
                byte b = 0;

                while (count >= 8)
                {

                    if (list[i]) { b |= 1; }
                    if (list[i + 1]) { b |= 2; }
                    if (list[i + 2]) { b |= 4; }
                    if (list[i + 3]) { b |= 8; }
                    if (list[i + 4]) { b |= 16; }
                    if (list[i + 5]) { b |= 32; }
                    if (list[i + 6]) { b |= 64; }
                    if (list[i + 7]) { b |= 128; }

                    this.writer.Write(b);
                    b = 0;
                    i += 8;
                    count -= 8;
                    
                }

                if (count > 0)
                {

                    for (byte j = 0; j < count; j++)
                    {
                        if (list[i + j]) { b |= Maths.Pow2B(j); }
                    }
                    this.writer.Write(b);
                    i += 8;
                    
                }
                
            }
            catch {  }

            return (i/8);

        }


        /// <summary>
        /// Generates a new seed for a random number generator and returns the value after writing to the packet writer.
        /// </summary>
        /// <returns>The newly generated seed.</returns>
        protected int WriteAndGetRandomSeed()
        {
            int seed = (int)Stopwatch.GetTimestamp();
            this.writer.Write(seed);
            return seed;
        }

        protected void WritePackedFloat(float f)
        {
            HalfSingle h = new HalfSingle(f);
            this.writer.Write(h.PackedValue);
        }

        protected void WritePackedVector2(Vector2 v)
        {
            HalfVector2 h = new HalfVector2(v);
            this.writer.Write(h.PackedValue);
        }

        protected void WritePackedVector3(Vector3 v)
        {
            HalfVector4 h = new HalfVector4(v.X,v.Y,v.Z,0);
            this.writer.Write(h.PackedValue);
        }

        protected void WritePackedVector4(Vector4 v)
        {
            HalfVector4 h = new HalfVector4(v);
            this.writer.Write(h.PackedValue);
        }

        #endregion
        
    }
   
}
